﻿Imports Aricie.DNN.Modules.LuceneSearch.ModuleProviders
Imports Aricie.DNN.Services
Imports DotNetNuke.Entities.Modules
Imports Aricie.Services
Imports System.Reflection
Imports Aricie.DNN.Modules.LuceneSearch.Business
Imports System.Linq
Imports Aricie.DNN.Modules.LuceneSearch.Settings
Imports Aricie.DNN.Settings

Namespace Aricie.DNN.Modules.LuceneSearch.Providers.Standalone

    Public Class DNN71StandaloneProvider
        Implements ILuceneStandAloneSearchable

        'Public Sub UpgradeSearchItem(portalId As Integer, ByRef searchItem As Aricie.DNN.Modules.LuceneSearch.Business.LuceneSearchItemInfo) Implements Aricie.DNN.Modules.LuceneSearch.ModuleProviders.ILuceneSearchableUpgrade.UpgradeSearchItem
        '    ' No upgrade to process, we're handling it already
        'End Sub

        Private Class BusinessControllerInformation
            Public Property BusinessControllerInstance As Object
            Public Property BusinessControllerIndexationMethod As MethodInfo

            Public Function InvokeBusinessControllerIndexationMethod(moduleInformation As ModuleInfo) As ICollection
                If (BusinessControllerInstance IsNot Nothing AndAlso BusinessControllerIndexationMethod IsNot Nothing) Then
                    Try
                        Return DirectCast(BusinessControllerIndexationMethod.Invoke(BusinessControllerInstance _
                                                                  , New Object() {moduleInformation, DateTime.MinValue}), ICollection)
                    Catch ex As Exception
                        ' we do nothing
                        Aricie.Services.ExceptionHelper.LogException(ex)
                    End Try
                End If
                Return New List(Of Object)() ' we return an empty list to ensure enumeration on the caller
            End Function

        End Class

        Private Class SearchDocumentPropertyHandler
            Private SearchDocumentPropertyCollection As New Dictionary(Of String, PropertyInfo)

            Public Function GetValueOf(propertyName As String, searchDocument As Object) As Object
                If (Not SearchDocumentPropertyCollection.ContainsKey(propertyName)) Then
                    SearchDocumentPropertyCollection.Add(propertyName, searchDocument.GetType().GetProperty(propertyName))
                End If

                Return SearchDocumentPropertyCollection(propertyName).GetValue(searchDocument, Nothing)
            End Function

        End Class

        Private Class SearchDocumentWrapper

            Private _searchDocument As Object
            Private _propertyHandler As SearchDocumentPropertyHandler

            Public Sub New(searchDocument As Object, propertyHandler As SearchDocumentPropertyHandler)
                _searchDocument = searchDocument
                _propertyHandler = propertyHandler
            End Sub

            Default Public ReadOnly Property SearchDocumentPropertyValue(propertyName As String) As Object
                Get
                    Return _propertyHandler.GetValueOf(propertyName, _searchDocument)
                End Get
            End Property
        End Class

        Private BusinessControllerInformationCollection As New Dictionary(Of DesktopModuleInfo, BusinessControllerInformation)
        Private Property searchDocumentCurrentPropertyHandler As New SearchDocumentPropertyHandler

        Public Function GetSearchItems(portalId As Integer) As DotNetNuke.Services.Search.SearchItemInfoCollection Implements Aricie.DNN.Modules.LuceneSearch.ModuleProviders.ILuceneStandAloneSearchable.GetSearchItems

            If NukeHelper.DnnVersion < New Version(7, 1) Then
                Return Nothing ' we're not working with a version of DNN that handles the new search type
            End If

            ' we go through all the controllers and check whether they have a base class named "ModuleSearchBase"
            Dim MC As New ModuleController
            Dim DMC As New DesktopModuleController()
            Dim searchItems As New DotNetNuke.Services.Search.SearchItemInfoCollection
            Dim SearchModuleType As Type = ReflectionHelper.CreateType("DotNetNuke.Entities.Modules.ModuleSearchBase, DotNetNuke")
            Dim settings As LucenePortalSettings = GetModuleSettings(Of LucenePortalSettings)(SettingsScope.PortalSettings, portalId)

            For Each moduleInfo As ModuleInfo In MC.GetSearchModules(portalId)
                Try
                    Dim moduleBusinessControllerInformation As BusinessControllerInformation = RetrieveModuleBusinessControllerInstance(DMC.GetDesktopModule(moduleInfo.DesktopModuleID))


                    If Not settings.IndexedModuleNames.Contains(moduleInfo.ModuleName) Then
                        Continue For
                    End If

                    If SearchModuleType.IsAssignableFrom(moduleBusinessControllerInformation.BusinessControllerInstance.GetType()) Then


                        Dim searchDocumentsFromModule As Object = moduleBusinessControllerInformation.BusinessControllerIndexationMethod.Invoke(moduleBusinessControllerInformation.BusinessControllerInstance _
                                                                                                                                                    , New Object() {moduleInfo, DateTime.MinValue})
                        For Each searchDocument As Object In moduleBusinessControllerInformation.InvokeBusinessControllerIndexationMethod(moduleInfo)
                            Dim searchItemInfo As New LuceneSearchItemInfo(portalId)
                            Dim documentWrapper As New SearchDocumentWrapper(searchDocument, searchDocumentCurrentPropertyHandler)

                            searchItemInfo.Author = Convert.ToInt32(documentWrapper("AuthorUserId"))
                            searchItemInfo.Content = Convert.ToString(documentWrapper("Body"))
                            searchItemInfo.Language = Convert.ToString(documentWrapper("CultureCode"))
                            searchItemInfo.Description = Convert.ToString(documentWrapper("Description"))
                            searchItemInfo.CanBeReturnedBySearch = Convert.ToBoolean(documentWrapper("IsActive"))
                            '"Keywords"
                            searchItemInfo.PubDate = Convert.ToDateTime(documentWrapper("ModifiedTimeUtc"))
                            '"ModuleDefId"
                            searchItemInfo.ModuleId = moduleInfo.ModuleID 'Convert.ToInt32(documentWrapper("ModuleId"))
                            '"NumericsKeys"
                            ' we handle the permissions here; only role permissions are defined in the search document
                            Dim searchDocumentPermissions As String = Convert.ToString(documentWrapper("Permissions"))
                            If (String.IsNullOrEmpty(searchDocumentPermissions)) Then
                                searchItemInfo.InheritModuleViewPermissions = True
                            Else
                                searchItemInfo.InheritModuleViewPermissions = False
                                searchItemInfo.ItemViewRoleIds.AddRange(searchDocumentPermissions.Split(New String() {";"}, StringSplitOptions.RemoveEmptyEntries).Select(Function(s) Convert.ToInt32(s)))
                            End If
                            '"PortalId"
                            searchItemInfo.GUID = Convert.ToString(documentWrapper("QueryString"))
                            '"RoleId"
                            '"SearchTypeId"
                            '"TabId"
                            searchItemInfo.ContentTaxonomy.AddRange(DirectCast(documentWrapper("Tags"), IEnumerable(Of String)))
                            searchItemInfo.Title = Convert.ToString(documentWrapper("Title"))
                            searchItemInfo.SearchKey = Convert.ToString(documentWrapper("UniqueKey"))
                            '"Url"

                            searchItems.Add(searchItemInfo)

                        Next
                    End If
                Catch ex As Exception
                Aricie.Services.ExceptionHelper.LogException(ex)
                Finally
                End Try
            Next

            Return searchItems

        End Function

        Private Function RetrieveModuleBusinessControllerInstance(moduleDesktopModuleInformation As DesktopModuleInfo) As BusinessControllerInformation
            If (Not BusinessControllerInformationCollection.ContainsKey(moduleDesktopModuleInformation)) Then

                Dim controllerInstance As Object = Nothing
                '  Dim getModifiedSeachDocumentsMethod As MethodInfo = Nothing
                Try
                    If (Not String.IsNullOrEmpty(moduleDesktopModuleInformation.BusinessControllerClass)) Then
                        controllerInstance = ReflectionHelper.CreateObject(moduleDesktopModuleInformation.BusinessControllerClass)
                        ' getModifiedSeachDocumentsMethod = controllerInstance.[GetType]().GetMethod("GetModifiedSearchDocuments")
                    End If
                Catch ex As Exception
                    Aricie.Services.ExceptionHelper.LogException(ex)
                End Try

                BusinessControllerInformationCollection.Add(moduleDesktopModuleInformation, New BusinessControllerInformation() With {.BusinessControllerInstance = controllerInstance, .BusinessControllerIndexationMethod = SearchMethod})

            End If
            Return BusinessControllerInformationCollection(moduleDesktopModuleInformation)
        End Function

        Private Shared _SearchMethod As MethodInfo
        Private Shared ReadOnly Property SearchMethod As MethodInfo
            Get
                If _SearchMethod Is Nothing Then
                    _SearchMethod = ReflectionHelper.CreateType("DotNetNuke.Entities.Modules.ModuleSearchBase, DotNetNuke").GetMethod("GetModifiedSearchDocuments")
                End If
                Return _SearchMethod
            End Get
        End Property

    End Class

End Namespace